﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;

namespace AnaxibiaStudios.Smug.Internal
{
  public class PropertyInfoEx : MemberInfoEx<PropertyInfo>
  {
    public bool IsIndexer { get { return Parameters.Length > 0; } }
    public MethodInfoEx Getter { get; protected set; }
    public MethodInfoEx Setter { get; protected set; }

    public PropertyInfoEx(MemberCollection parent, PropertyInfo prop)
      : base(parent, prop)
    {
      Getter = MemberInfoEx.Wrap(parent, prop.GetGetMethod(true));
      Setter = MemberInfoEx.Wrap(parent, prop.GetSetMethod(true));
      var rep = MemberInfoEx.SelectMorePublic(Getter, Setter) as MethodInfoEx;
      SetModifiers(rep.Info);

      SetParameters(prop.PropertyType, prop.GetIndexParameters());
      Name = IsIndexer ? "Item" : Name; // reflected name is irrelevent if indexer
    }

    protected override bool MatchesNonOverload(MemberInfoEx that)
    {
      var pex = that as PropertyInfoEx;
      if (pex == null)
        return false;

      return
        ReturnType == pex.ReturnType &&
        SharedAccess(this, that) &&
        SharedAccess(Getter, pex.Getter) &&
        SharedAccess(Setter, pex.Setter);
    }

    protected override bool IsOverloadable()
    {
      return IsIndexer;
    }

    protected override Scope ArgumentScope()
    {
      return new Scope(IsIndexer ? Scope.WrapTypeEnum.Square : Scope.WrapTypeEnum.Empty);
    }

    public override string BuildBody()
    {
      Func<bool, string> getPropParams = ignoreTypes => IsIndexer ? Scope.Square(BuildParams(new ParameterOptions() { IgnoreTypes = ignoreTypes })) : string.Empty;
      var builder = _parent.Builder;
      
      var propBody = new Scope(Scope.WrapTypeEnum.Brackets);
      string invoke = IsIndexer ? getPropParams(true) : (SourceBuilder.Dot + Name);

      propBody.Add(builder.BuildGet(this, invoke));
      propBody.Add(builder.BuildSet(this, invoke));
      return propBody.ToString();
    }
  }
}
